from app import dBSession
from sqlalchemy import desc, asc, and_
from app.Models.BaseModel import BaseModel
from sqlalchemy_serializer import SerializerMixin
from app.Vendor.Decorator import classTransaction
from app.Models.Model import React


class Reaction(React, BaseModel, SerializerMixin):
    def getOne(self, filters, order='id desc', field=()):
        res = dBSession.query(Reaction).filter(*filters)
        order = order.split(' ')
        if order[1] == 'desc':
            res = res.order_by(desc(order[0])).first()
        else:
            res = res.order_by(asc(order[0])).first()
        if res == None:
            return None
        if not field:
            res = res.to_dict()
        else:
            res = res.to_dict(only=field)
        return res

    def getAll(self, filters, order='id desc', field=()) -> list:
        """
        查询全部
        @param object cls_ 数据库模型实体类
        @param set filters 查询条件
        @param str order 排序
        @param tuple field 字段
        @param int $limit 取多少条
        @return dict
        """
        if not filters:
            res = dBSession.query(Reaction)
        else:
            res = dBSession.query(Reaction).filter(*filters)
        orderArr = order.split(' ')
        if orderArr[1] == 'desc':
            res = res.order_by(desc(orderArr[0])).all()
        else:
            res = res.order_by(asc(orderArr[0])).all()
        if not field:
            res = [c.to_dict() for c in res]
        else:
            res = [c.to_dict(only=field) for c in res]
        return res

    def getList(self, reaction_pairs_list, cpd_list, interaction_list):
        trueReactionList = []
        trueCpdList = []

        # 查询reaction可能存在的路径
        for pair in reaction_pairs_list:
            reactions = self.getAll(
                {
                    Reaction.title.like("%" + pair + "%")
                }
            )

            # pair的信息
            pair_information = reaction_pairs_list[pair]
            cpd1 = pair_information[1]
            cpd2 = pair_information[2]

            # 进行边的验证
            if (reactions is not None):
                for single_r in reactions:
                    # 提取reaction路径的坐标
                    coords_text = single_r.get('data_coords')
                    coords = coords_text.split(",")
                    # 将路径两两进行分开进行，reaction_path为此reaction的列表
                    reaction_path = []
                    # 把第一对进行添加
                    reaction_path.append([coords[0], coords[1]])
                    # 按照四个一组分割
                    l = int(len(coords) / 4)
                    # i代表此reaction查询到的pathway的点的个数
                    for pair in range(l):
                        reaction_path.append([coords[(pair + 1) * 4 - 2], coords[(pair + 1) * 4 - 1]])
                    # 获取对应的cpd的信息
                    cpd1_imformations = cpd_list[cpd1]
                    cpd2_imformations = cpd_list[cpd2]
                    for cpd1_imformation in cpd1_imformations:
                        for cpd2_imformation in cpd2_imformations:
                            cpd1_data_coords = [cpd1_imformation[0], cpd1_imformation[1]]
                            cpd2_data_coords = [cpd2_imformation[0], cpd2_imformation[1]]
                            # cpd击中的路径的标记
                            cpd1_flag = False
                            cpd2_flag = False
                            # 遍历所有路径上的点，确认是否集中
                            for point_coord in reaction_path:
                                if int(point_coord[0]) >= int(cpd1_data_coords[0]) - 5 and int(point_coord[0]) <= int(
                                        cpd1_data_coords[0]) + 5 and int(
                                    point_coord[1]) >= int(cpd1_data_coords[1]) - 5 and int(point_coord[1]) <= int(
                                    cpd1_data_coords[1]) + 5:
                                    cpd1_flag = True
                                if int(point_coord[0]) >= int(cpd2_data_coords[0]) - 5 and int(point_coord[0]) <= int(
                                        cpd2_data_coords[0]) + 5 and int(
                                    point_coord[1]) >= int(cpd2_data_coords[1]) - 5 and int(point_coord[1]) <= int(
                                    cpd2_data_coords[1]) + 5:
                                    cpd2_flag = True
                            if cpd1_flag and cpd2_flag:
                                # 去重
                                trueReactionList.append(reaction_path)
                                if interaction_list.__contains__([cpd1, cpd2]):
                                    interaction_list.remove([cpd1, cpd2])
                                # 选择是否将所有点添加进去
                                trueCpdList.append(cpd1_imformation)
                                trueCpdList.append(cpd2_imformation)
        new_trueReactionList = self.list_reduce(trueReactionList)
        new_trueCpdList = self.list_reduce(trueCpdList)

        maybe_path, maybe_node = self.not_in_path(cpd_list, interaction_list)

        # 把真实存在的和可能存在的进行区分
        maybe_node = self.maybe_node_list_reduce(new_trueCpdList, maybe_node)

        return new_trueReactionList, new_trueCpdList, maybe_path, maybe_node

    # 对多重嵌套的列表进行去重
    def list_reduce(self, raw_list):
        new_list = []
        test_set = set()

        for i, k in enumerate(raw_list):
            if test_set.__contains__(k.__str__()):
                pass
            else:
                new_list.append(raw_list[i])
                test_set.add(k.__str__())

        return new_list

    # 对maybe_cpd的列表进行去重
    def maybe_node_list_reduce(self, true_list, maybe_list):
        new_list = []

        true_list = [k.__str__ for k in true_list]

        for i, k in enumerate(maybe_list):
            if true_list.__contains__(k.__str__()):
                pass
            else:
                new_list.append(k)

        return new_list

    def not_in_path(self, cpd_list, interaction_list):
        # 遍历还没有连上的interaction_list，查找cpd_list中cpd的位置，想办法给他连上

        maybe_path = []
        maybe_node = []

        for interaction in interaction_list:
            cpd1_imformations = cpd_list[interaction[0]]
            cpd2_imformations = cpd_list[interaction[1]]



            for cpd1_imformation in cpd1_imformations:
                for cpd2_imformation in cpd2_imformations:
                    # 添加到可能存在的node里
                    maybe_node.append(cpd1_imformation)
                    maybe_node.append(cpd2_imformation)

                    cpd1_data_coords = [cpd1_imformation[0], cpd1_imformation[1]]
                    cpd2_data_coords = [cpd2_imformation[0], cpd2_imformation[1]]
                    maybe_path.append([cpd1_data_coords, cpd2_data_coords])

        return self.list_reduce(maybe_path), self.list_reduce(maybe_node)
